package com.nav.brainfuckeditor.editors;

import org.eclipse.jface.text.*;

public class BFDoubleClickStrategy implements ITextDoubleClickStrategy {
	protected ITextViewer fText;

	public void doubleClicked(ITextViewer part) {
		int pos = part.getSelectedRange().x;

		if (pos < 0)
			return;

		fText = part;

		int newPos = closestNonSpaceCharPos(pos);
		selectWord(newPos);
	}
	private int closestNonSpaceCharPos(int pos) {
		IDocument doc = fText.getDocument();
		try {
			int lpos = pos - 1, rpos = pos;
			while(lpos >= 0 && Character.isWhitespace(doc.getChar(lpos)))
				lpos--;
			while(rpos < doc.getLength() && Character.isWhitespace(doc.getChar(rpos)))
				rpos++;
			int ldist = lpos < 0 ? Integer.MAX_VALUE : pos - lpos - 1, rdist = rpos >= doc.getLength() ? Integer.MAX_VALUE : rpos - pos;
			if(lpos < 0 && rpos >= doc.getLength())
				return pos;
			if(ldist < rdist)
				return lpos;
			if(ldist > rdist || doc.getChar(rpos) == IBFCharConstants.BF_CLOSE)
				return rpos;
			return lpos;
		} catch(BadLocationException e) {
			// not expecting as the pos value is always correct, therefore ignoring
		}
		return pos;
	}
	private boolean isBFChar(char c) {
		return c == IBFCharConstants.BF_OPEN || c == IBFCharConstants.BF_CLOSE || isNonBraceBFChar(c);
	}
	private boolean isNonBraceBFChar(char c) {
		return c == IBFCharConstants.BF_LEFT || c == IBFCharConstants.BF_RIGHT || c == IBFCharConstants.BF_OUTPUT || c == IBFCharConstants.BF_INPUT || c == IBFCharConstants.BF_INCREASE || c == IBFCharConstants.BF_DECREASE;
	}
	private void selectWord(int pos) {
		try {
			IDocument doc = fText.getDocument();
			char c = doc.getChar(pos);
			if(isBFChar(c))
				selectBFWord(pos);
			else
				selectCommentWord(pos);
		} catch(BadLocationException e) {
			// not expecting as the pos value is always correct, therefore ignoring
		}
	}
	private void selectBFWord(int pos) {
		IDocument doc = fText.getDocument();
		int startPos = pos, endPos = pos;
		try {
			char c = doc.getChar(pos);
			if(c == IBFCharConstants.BF_OPEN) {
				// select all the characters until matching end brace or end of the document
				int ib = 1;
				while(++endPos < doc.getLength()) {
					char ch = doc.getChar(endPos);
					if(ch == IBFCharConstants.BF_OPEN)
						ib++;
					else if(ch == IBFCharConstants.BF_CLOSE) {
						if(--ib == 0)
							break;
					}
				}
			} else if(c == IBFCharConstants.BF_CLOSE) {
				// select all the characters until matching open brace or start of the document
				int ib = 1;
				while(--startPos >= 0) {
					char ch = doc.getChar(startPos);
					if(ch == IBFCharConstants.BF_CLOSE)
						ib++;
					else if(ch == IBFCharConstants.BF_OPEN) {
						if(--ib == 0)
							break;
					}
				}
			} else {
				// select all the BF characters to the left and right
				do {
					startPos--;
				} while(startPos >= 0 && isNonBraceBFChar(doc.getChar(startPos)));
				do {
					endPos++;
				} while(endPos < doc.getLength() && isNonBraceBFChar(doc.getChar(endPos)));
			}
		} catch(BadLocationException e) {
			// not expecting as the pos value is always correct, therefore ignoring
		}
		selectRange(startPos, endPos);
	}
	protected boolean selectCommentWord(int caretPos) {

		IDocument doc = fText.getDocument();
		int startPos, endPos;

		try {

			int pos = caretPos;
			char c;

			while (pos >= 0) {
				c = doc.getChar(pos);
				if (!Character.isJavaIdentifierPart(c))
					break;
				--pos;
			}

			startPos = pos;

			pos = caretPos;
			int length = doc.getLength();

			while (pos < length) {
				c = doc.getChar(pos);
				if (!Character.isJavaIdentifierPart(c))
					break;
				++pos;
			}

			endPos = pos;
			selectRange(startPos, endPos);
			return true;

		} catch (BadLocationException x) {
		}

		return false;
	}

	private void selectRange(int startPos, int stopPos) {
		int offset = startPos + 1;
		int length = stopPos - offset;
		fText.setSelectedRange(offset, length);
	}
}